home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / EAGLE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-28  |  25.2 KB  |  849 lines

  1. #ifdef MSDOS
  2. /*
  3.  * Interface driver for the EAGLE board for KA9Q's TCP/IP on an IBM-PC ONLY!
  4.  *
  5.  *  Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
  6.  *  Permission for non-commercial use is hereby granted provided this notice
  7.  *  is retained.  For info call: (301) 997-3838.
  8.  *
  9.  *  10 Jan 88    ng6q    - Corrected IDLE comparison in doegstat.
  10.  *   6 Apr 88    ng6q    - Changed eg_raw to prevent calling egtxint with a
  11.  *              packet in sndbuf.  Initialized sndq and rcvq in
  12.  *              eg_attach.  Added carrier detect check before
  13.  *              slot time delay in egtxint.  Should make major
  14.  *              changes to egtxint to avoid delay loops while
  15.  *              masked for receive interrupts.
  16.  */
  17.  
  18. #include "global.h"
  19. #ifdef EAGLE
  20. #include <dos.h>
  21. #include "mbuf.h"
  22. #include "iface.h"
  23. #include "pktdrvr.h"
  24. #include "netuser.h"
  25. #include "eagle.h"
  26. #include "z8530.h"
  27. #include "ax25.h"
  28. #include "trace.h"
  29. #include "pc.h"
  30. #include "devparam.h"
  31. #include <time.h>
  32.  
  33. #if !defined(_lint)
  34. static char rcsid[] OPTIONAL = "$Id: eagle.c,v 1.12 1996/12/29 02:47:22 root Exp root $";
  35. #endif
  36.  
  37. static int32 eg_ctl (struct iface *iface,int cmd,int set,int32 val);
  38. static int eg_raw (struct iface *iface,struct mbuf *bp);
  39. static int eg_stop (struct iface *iface);
  40. static void egchanparam (struct egchan *hp);
  41. static void egexint (struct egchan *hp);
  42. static void egrxint (struct egchan *hp);
  43. static void egtxint (struct egchan *hp);
  44. static void rts (struct egchan *hp,int16 x);
  45. static void waitmsec (int n);
  46.  
  47. static struct EGTAB Eagle[EGMAX];    /* Device table - one entry per card */
  48. static void (*eghandle[])() = {    /* handler interrupt vector table */
  49.     eg0vec,    
  50. };
  51. static struct egchan Egchan[2*EGMAX];    /* channel table - 2 entries per card */
  52. static int16 Egnbr;
  53.  
  54. /* Master interrupt handler.  One interrupt at a time is handled.
  55.  * here. Service routines are called from here.
  56.  */
  57. void
  58. egint(dev)
  59. int dev;
  60. {
  61.     register char st;
  62.     register int16 pcbase;
  63.     struct egchan *hp;
  64.  
  65.     Eagle[dev].ints++;
  66.     pcbase = Eagle[dev].addr;
  67.  
  68.     /* Read interrupt status register from channel A */
  69.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0) {
  70.         /* Use IFs to process ALL interrupts pending
  71.          * because we need to check all interrupt conditions
  72.          */
  73.         if (st & CHARxIP) {
  74.             /* Channel A Rcv Interrupt Pending */
  75.             hp = &Egchan[2 * dev];
  76.             egrxint(hp);
  77.         } else if (st & CHATxIP) {
  78.             /* Channel A Transmit Int Pending */
  79.             hp = &Egchan[2 * dev];
  80.             egtxint(hp);
  81.         } else if (st & CHAEXT) {
  82.             /* Channel A External Status Int */
  83.             hp = &Egchan[2 * dev];
  84.             egexint(hp);
  85.         } else if (st & CHBRxIP) {
  86.             /* Channel B Rcv Interrupt Pending */
  87.             hp = &Egchan[(2 * dev)+1];
  88.             egrxint(hp);
  89.         } else if (st & CHBTxIP) {
  90.             /* Channel B Transmit Int Pending */
  91.             hp = &Egchan[(2 * dev)+1];
  92.             egtxint(hp);
  93.         } else if (st & CHBEXT) {
  94.             /* Channel B External Status Int */
  95.             hp = &Egchan[(2 * dev)+1];
  96.             egexint(hp);
  97.         }
  98.         /* Reset highest interrupt under service */
  99.         write_scc(hp->base+CTL,R0,RES_H_IUS);
  100.     } /* End of while loop on int processing */
  101. }
  102.  
  103. /* Eagle SIO External/Status interrupts
  104.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  105.  * Receiver automatically goes to Hunt on an abort.
  106.  *
  107.  * If the Tx Underrun interrupt hits, change state and
  108.  * issue a reset command for it, and return.
  109.  */
  110. static void
  111. egexint(hp)
  112. register struct egchan *hp;
  113. {
  114.     char st, i_state;
  115.  
  116.     i_state = disable ();        /* disable interrupts */
  117.     hp->exints++;
  118.     st = read_scc(hp->base+CTL,R0);     /* Fetch status */
  119.  
  120.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  121.     if((hp->rstate==0) && (st & TxEOM)) {
  122.         /* if in UNDERRUN, go to FLAGOUT state
  123.          * see explanation under egtxint()
  124.          * CRC & FLAG now going out, so
  125.          * wait for Tx BUffer Empty int
  126.          */
  127.  
  128.         /* If we are not in underrun, this is an unexpected
  129.          * underrun.  EOM bit should be set, so the SCC will
  130.          * now send an abort
  131.          */
  132.  
  133.         if(hp->tstate == UNDERRUN)
  134.             hp->tstate = FLAGOUT;
  135.  
  136.         /* Tx Buff EMPTY interrupt occurs after CRC is sent */
  137.     }
  138.  
  139.     /* Receive Mode only
  140.      * This triggers when hunt mode is entered, & since an ABORT
  141.      * automatically enters hunt mode, we use that to clean up
  142.      * any waiting garbage
  143.      */
  144.     if((hp->rstate == ACTIVE) && (st & BRK_ABRT)) {
  145.         hp->rcp = hp->rcvbuf->data;
  146.         hp->rcvbuf->cnt = 0;          /* rewind on DCD transition */
  147.         hp->aborts++;              /* nbr aborts * 2 */
  148.     }
  149.  
  150.     /* reset external status latch */
  151.     write_scc(CTL+hp->base,R0,RES_EXT_INT);
  152.  
  153.     restore(i_state);
  154. }
  155.  
  156. /* EG receive interrupt handler. The first receive buffer is pre-allocated
  157.  * in the init routine.  Thereafter, it is filled here, queued out, and a
  158.  * new one acquired.  CRC, OVERRUN and TOOBIG errors merely 'rewind' the
  159.  * pointers and reuse the same buffer.
  160.  */
  161. static void
  162. egrxint(hp)
  163. register struct egchan *hp;
  164. {
  165.     register int16 base;
  166.     char rse, i_state;
  167.     struct mbuf *bp;
  168.     struct phdr phdr;
  169.  
  170.     i_state = disable ();        /* disable interrupts */
  171.     hp->rxints++;
  172.     base = hp->base;
  173.  
  174.     if ((read_scc(base+CTL,R0)) & Rx_CH_AV) {
  175.         /* there is a char to be stored
  176.          * read special condition bits before reading the data char
  177.          */
  178.         rse = read_scc(hp->base+CTL,R1); /* get status byte from R1 */
  179.         if(rse & Rx_OVR) {
  180.             /* Rx overrun - toss buffer */
  181.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  182.             hp->rcvbuf->cnt = 0;
  183.             hp->rstate = RXERROR;    /* set error flag */
  184.             hp->rovers++;        /* count overruns */
  185.         } else if(hp->rcvbuf->cnt >= hp->bufsiz) {
  186.             /* Too large -- toss buffer */
  187.             hp->toobig++;
  188.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  189.             hp->rcvbuf->cnt = 0;
  190.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  191.         }
  192.         /* ok, we can store the received character now */
  193.         if(hp->rstate == ACTIVE) {        /* If no errors... */
  194.             *hp->rcp++ = inportb(base+DATA);    /* char to rcv buff */
  195.             hp->rcvbuf->cnt++;            /* bump count */
  196.         } else {
  197.             /* got to empty FIFO */
  198.             (void) inportb(base+DATA);
  199.             write_scc(hp->base+CTL,R0,ERR_RES);    /* reset err latch */
  200.             hp->rstate = ACTIVE;
  201.         }
  202.     }
  203.     /* char has been stored
  204.      * read special condition bits
  205.      */
  206.     rse = read_scc(hp->base+CTL,R1);     /* get status byte from R1 */
  207.  
  208.     /* The End of Frame bit is ALWAYS associated with a character,
  209.      * usually, it is the last CRC char.  Only when EOF is true can
  210.      * we look at the CRC byte to see if we have a valid frame
  211.      */
  212.     if(rse & END_FR) {
  213.         hp->rxframes++;
  214.         /* END OF FRAME -- Make sure Rx was active */
  215.         if(hp->rcvbuf->cnt > 0) {        /* any data to store */
  216.             /* looks like a frame was received
  217.              * now is the only time we can check for CRC error
  218.              */
  219.             if((rse & CRC_ERR) || (hp->rstate > ACTIVE) || (hp->rcvbuf->cnt < 10)) {
  220.                 /* error occurred; toss frame */
  221.                 if(rse & CRC_ERR)
  222.                     hp->crcerr++;    /* count CRC errs */
  223.                 if(hp->rstate == RXERROR)
  224.                     hp->rovers++;
  225.                 /* don't throw away buffer -
  226.                  * merely reset the pointers
  227.                  */
  228.                 hp->rcp = hp->rcvbuf->data;
  229.                 hp->rcvbuf->cnt = 0;
  230.             } else {
  231.                 /* Here we have a valid frame */
  232.                 hp->rcvbuf->cnt -= 2;           /* Toss 2 crc bytes */
  233.                 if((bp = alloc_mbuf(sizeof(phdr))) != NULLBUF){
  234.                     bp->cnt = sizeof(phdr);
  235.                     phdr.type = CL_AX25;
  236.                     phdr.iface = hp->iface;
  237.                     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  238.                     bp->next = hp->rcvbuf;
  239.                     enqueue(&Hopper,bp);       /* queue it in */
  240.                 } else
  241.                     free_p(hp->rcvbuf);
  242.                 /* packet queued - get buffer for next frame */
  243.                 hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  244.                 hp->rcp = hp->rcvbuf->data;
  245.                 hp->rcvbuf->cnt = 0;
  246.                 if(hp->rcvbuf == NULLBUF) {
  247.                     /* No memory, abort receiver */
  248.                     restore(i_state);
  249.                     tputs("DISASTER! Out of Memory for Receive!\n");
  250.                     write_scc(CTL+base,R3,Rx8);
  251.                     return;
  252.                 }
  253.             } /* end good frame queued */
  254.         }  /* end check for active receive upon EOF */
  255.         hp->rstate = ACTIVE;    /* and clear error status */
  256.     } /* end EOF check */
  257.     restore(i_state);
  258. }
  259.  
  260. /* egchan transmit interrupt service routine
  261.  *
  262.  * The state variable tstate, along with some static pointers,
  263.  * represents the state of the transmit "process".
  264.  */
  265. static void
  266. egtxint(hp)
  267. register struct egchan *hp;
  268. {
  269.     register int16 base;
  270.     char i_state;
  271.     int c;
  272.  
  273.     i_state = disable ();
  274.  
  275.     if(hp->tstate != DEFER && hp->tstate)
  276.         hp->txints++;
  277.     base = hp->base;
  278.  
  279.     switch(hp->tstate) {
  280.     case FLAGOUT:
  281.         /* Here after CRC sent and Tx interrupt fires.
  282.          * To give the SCC a chance to get the FLAG
  283.          * out, we delay 100 Ms
  284.          */
  285.         hp->tstate = IDLE;    /* fall thru to IDLE */
  286.         waitmsec(10);        /* 100 msec wait for flag Tx */
  287.         /* Note, it may be possible to stuff out a
  288.          * meaningless character, wait for the interrupt
  289.          * then go to idle.  A delay is absolutely necessary
  290.          * here else the packet gets truncated prematurely
  291.          * when no other packet is waiting to be sent.
  292.          * IDLE state indicates either we are starting a brand new packet
  293.          * as a result of its being queued for transmission (egtxint called
  294.          * from eg_raw), or after a frame has been transmitted (as a
  295.          * result of a Tx buffer empty interrupt after the CRC/FLAG
  296.          */
  297.     case IDLE:
  298.         /* Transmitter idle. Find a frame for transmission */
  299.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF) {
  300.             /* Nothing to send - return to receive mode
  301.              * Tx OFF now - flag should have gone
  302.              */
  303.             rts(hp,OFF);
  304.             restore(i_state);
  305.             return;
  306.         }
  307.         /* If a buffer to send, we drop thru here */
  308.     case DEFER:        /* we may have deferred prev xmit attempt */
  309.         /* PPERSIST CALCULATION: we use the lower byte of the
  310.          * 8253 timer 0 count, as a random number (0-255).
  311.          * If the persist value is higher, wait one slot time
  312.          */
  313.         if(hp->persist >= peekb(0x40,0x6c))
  314.             waitmsec(hp->slotime);
  315.  
  316.         /* Check DCD so we don't step on a frame being received */
  317.         /* DCD is ACTIVE LOW on the SCC DCD pin, but the bit in R0 */
  318.         /* is SET when DCD is ACTIVE!! */
  319.  
  320.         if((read_scc(base+CTL,R0) & DCD) > 0) { /* Carrier Detected? */
  321.             hp->tstate = DEFER;    /* defer xmit */
  322.             /* don't release dequeued buffer...*/
  323.             restore(i_state);
  324.             return;
  325.         }
  326.  
  327.         rts(hp,ON);   /* Transmitter on */
  328.         /* ints not enabled yet */
  329.  
  330.         /* Get next char to send */
  331.         c = PULLCHAR(&hp->sndbuf);        /* one char at a time */
  332.         write_scc(CTL+base,R0,RES_Tx_CRC);    /* reset for next frame */
  333.         outportb(base+DATA,c);        /* First char out now */
  334.  
  335.         /* select transmit interrupts to enable */
  336.  
  337.         write_scc(CTL+base,R15,TxUIE);        /* allow Underrun int only */
  338.         write_scc(CTL+base,R1,TxINT_ENAB|EXT_INT_ENAB);  /* Tx/Extern ints on */
  339.         write_scc(CTL+base,R9,MIE|NV);        /* master enable */
  340.         /* enable interrupt latch on board */
  341.         outportb(hp->dmactrl,INTENABLE);
  342.  
  343.         hp->tstate = ACTIVE;    /* char going out now */
  344.         restore(i_state);
  345.         return;
  346.  
  347.     case ACTIVE:
  348.         /* Here we are actively sending a frame */
  349.         if((c = PULLCHAR(&hp->sndbuf)) != -1){
  350.             outportb(hp->base+DATA,c);    /* next char is gone */
  351.             /* stuffing a char satisfies Interrupt condition */
  352.         } else {
  353.             /* No more to send - just stop till underrun int */
  354.             hp->tstate = UNDERRUN;
  355.             free_p(hp->sndbuf);
  356.             /* now we reset the EOM latch & enable underrun int */
  357.             write_scc(CTL+base,R0,RES_EOM_L);    /* send CRC at underrun */
  358.             write_scc(CTL+hp->base,R0,RES_Tx_P); /* reset Tx Int Pend */
  359.         }
  360.         restore(i_state);
  361.         return;     /* back to wait for interrupt */
  362.  
  363.     case UNDERRUN:
  364.         /*
  365.          * This state is handled by an UNDERRUN interrupt, which
  366.          * is an External Status interrupt.  At UNDERRUN, the
  367.          * UNDERRUN/EOM latch in R0 will be 0, so the SCC will send
  368.          * CRC and ending flag.  After the CRC clears the Tx buffer,
  369.          * a TX BUFF EMPTY interrupt will fire.  At that time, we
  370.          * should be in FLAGOUT state, ready to send another frame
  371.          * if one is there to send.
  372.          */
  373.         break;
  374.     } /* end switch */
  375.     restore(i_state);
  376. }
  377.  
  378. /* SET Transmit or Receive Mode
  379.  * Set RTS (request-to-send) to modem on Transmit
  380.  */
  381. static void
  382. rts(hp,x)
  383. register struct egchan *hp;
  384. int16 x;
  385. {
  386. int16 tc;
  387. long br;
  388.  
  389.     /* Reprogram BRG and turn on transmitter to send flags */
  390.     if(x == ON) {                /* Turn Tx ON and Receive OFF */
  391.         write_scc(CTL+hp->base,R3,Rx8);    /* Rx off */
  392.         waitmsec(50);            /* 500 msec delay before on */
  393.         hp->rstate = IDLE;
  394.         write_scc(CTL+hp->base,R9,0);    /* Interrupts off */
  395.         br = hp->speed;         /* get desired speed */
  396.         tc = (XTAL/br)-2;        /* calc 1X BRG divisor */
  397.         write_scc(CTL+hp->base,R12,tc&0xFF);      /* lower byte */
  398.         write_scc(CTL+hp->base,R13,(tc>>8)&0xFF); /* upper bite */
  399.  
  400.         write_scc(CTL+hp->base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);
  401.         /* Transmitter now on */
  402.         write_scc(CTL+hp->base,R0,RES_Tx_CRC);/* CRC reset */
  403.         waitmsec(hp->txdelay);      /* Delay after Tx on */
  404.     } else {    /* Tx OFF and Rx ON */
  405.         hp->tstate = IDLE;
  406.         write_scc(CTL+hp->base,R5,Tx8|DTR);     /* TX off now */
  407.         write_scc(CTL+hp->base,R0,ERR_RES);     /* reset error bits */
  408.  
  409.         write_scc(CTL+hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  410.         write_scc(CTL+hp->base,R15,BRKIE);        /* allow ABORT int */
  411.  
  412.         /* delay for squelch tail before enable of Rx */
  413.         waitmsec(hp->squeldelay);    /* keep it up  */
  414.  
  415.         /* Reprogram BRG for 32x clock for receive DPLL */
  416.         write_scc(CTL+hp->base,R14,BRSRC);         /* BRG off, but keep Pclk source */
  417.         br = hp->speed;             /* get desired speed */
  418.         tc = ((XTAL/32)/br)-2;            /* calc 32X BRG divisor */
  419.         write_scc(CTL+hp->base,R12,tc&0xFF);    /* lower byte */
  420.         write_scc(CTL+hp->base,R13,(tc>>8)&0xFF);    /* upper bite */
  421.         write_scc(CTL+hp->base,R14,BRSRC|SEARCH);    /* SEARCH mode, keep BRG source */
  422.         write_scc(CTL+hp->base,R14,BRSRC|BRENABL);    /* Enable the BRG */
  423.  
  424.         /* Now, turn on the receiver and hunt for a flag */
  425.         write_scc(CTL+hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  426.         hp->rstate = ACTIVE;            /* Normal state */
  427.     }
  428. }
  429.  
  430. /* Initialize eg controller parameters */
  431. static void
  432. egchanparam(hp)
  433. register struct egchan *hp;
  434. {
  435.     int16 tc;
  436.     long br;
  437.     char i_state;
  438.     register int16 base;
  439.  
  440.     /* Initialize 8530 channel for SDLC operation */
  441.  
  442.     base = hp->base;
  443. #ifdef    notdef
  444.     tprintf("Initializing Channel %c - Base = %x\n",base&2?'A':'B',base);
  445. #endif
  446.     i_state = disable ();
  447.  
  448.     switch(base & 2){
  449.     case 2:
  450.         write_scc(CTL+base,R9,CHRA);    /* Reset channel A */
  451.         break;
  452.     case 0:
  453.         write_scc(CTL+base,R9,CHRB);    /* Reset channel B */
  454.         break;
  455.     }
  456.  
  457.     /* Deselect all Rx and Tx interrupts */
  458.     write_scc(CTL+base,R1,0);
  459.  
  460.     /* Turn off external interrupts (like CTS/CD) */
  461.     write_scc(CTL+base,R15,0);
  462.  
  463.     /* X1 clock, SDLC mode */
  464.     write_scc(CTL+base,R4,SDLC|X1CLK);           /* SDLC mode and X1 clock */
  465.  
  466.     /* Now some misc Tx/Rx parameters */
  467.     /* CRC PRESET 1, NRZI Mode */
  468.     write_scc(CTL+base,R10,CRCPS|NRZI);
  469.  
  470.     /* Set up BRG and DPLL multiplexers */
  471.     /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
  472.     write_scc(CTL+base,R11,TCBR|RCDPLL|TRxCDP|TRxCOI);
  473.  
  474.     /* Null out SDLC start address */
  475.     write_scc(CTL+base,R6,0);
  476.  
  477.     /* SDLC flag */
  478.     write_scc(CTL+base,R7,FLAG);
  479.  
  480.     /* Set up the Transmitter but don't enable it */
  481.     /*  DTR, 8 bit TX chars only - TX NOT ENABLED */
  482.     write_scc(CTL+base,R5,Tx8|DTR);
  483.  
  484.     /* Receiver - intial setup only - more later */
  485.     write_scc(CTL+base,R3,Rx8);            /* 8 bits/char */
  486.  
  487.     /* Setting up BRG now - turn it off first */
  488.     write_scc(CTL+hp->base,R14,BRSRC);         /* BRG off, but keep Pclk source */
  489.  
  490.     /* set the 32x time constant for the BRG in Receive mode */
  491.  
  492.     br = hp->speed;             /* get desired speed */
  493.     tc = ((XTAL/32)/br)-2;            /* calc 32X BRG divisor */
  494.  
  495.     write_scc(CTL+hp->base,R12,tc&0xFF);      /* lower byte */
  496.     write_scc(CTL+hp->base,R13,(tc>>8)&0xFF); /* upper bite */
  497.  
  498.     /* Time to set up clock control register for RECEIVE mode
  499.      * Eagle has xtal osc going to pclk at 3.6864 Mhz
  500.      * The BRG is sourced from that, and set to 32x clock
  501.      * The DPLL is sourced from the BRG, and feeds the TRxC pin
  502.      * Transmit clock & Receive clock come from DPLL
  503.      */
  504.  
  505.     /* Following subroutine sets up and ENABLES the receiver */
  506.     rts(hp,OFF);           /* TX OFF and RX ON */
  507.  
  508.     write_scc(CTL+hp->base,R14,BRSRC|SSBR);       /* DPLL from BRG, BRG source is PCLK */
  509.     write_scc(CTL+hp->base,R14,BRSRC|SEARCH);       /* SEARCH mode, keep BRG source */
  510.  
  511.     write_scc(CTL+hp->base,R14,BRSRC|BRENABL);    /* Enable the BRG */
  512.  
  513.     /* enable the receive interrupts */
  514.  
  515.     write_scc(CTL+hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  516.     write_scc(CTL+hp->base,R15,BRKIE);        /* ABORT int */
  517.     write_scc(CTL+hp->base,R9,MIE|NV);    /* master enable */
  518.  
  519.     /* enable interrupt latch on board */
  520.     outportb(hp->dmactrl,INTENABLE);
  521.  
  522.     /* Now, turn on the receiver and hunt for a flag */
  523.     write_scc(CTL+hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  524.  
  525.     restore(i_state);
  526. }
  527.  
  528. /* Attach a EAGLE interface to the system
  529.  * argv[0]: hardware type, must be "eagle"
  530.  * argv[1]: I/O address, e.g., "0x300"
  531.  * argv[2]: vector, e.g., "2"
  532.  * argv[3]: mode, must be:
  533.  *        "ax25" (AX.25 UI frame format)
  534.  * argv[4]: interface label, e.g., "eg0"
  535.  * argv[5]: receiver packet buffer size in bytes
  536.  * argv[6]: maximum transmission unit, bytes
  537.  * argv[7]: interface speed, e.g, "1200"
  538.  * argv[8]: First IP address, optional (defaults to Ip_addr);
  539.  * argv[9]: Second IP address, optional (defaults to Ip_addr);
  540.  */
  541. int
  542. eg_attach(argc,argv,p)
  543. int argc;
  544. char *argv[];
  545. void *p;
  546. {
  547.     register struct iface *if_pca,*if_pcb;
  548.     struct egchan *hp;
  549.     int dev;
  550.     char *cp;
  551.  
  552.     /* Quick check to make sure args are good and mycall is set */
  553.     if(strcmp(argv[3],"ax25") != 0){
  554.         tprintf("Mode %s unknown for interface %s\n",
  555.             argv[3],argv[4]);
  556.         return -1;
  557.     }
  558.     if(if_lookup(argv[4]) != NULLIF){
  559.         tprintf(Existingiface,argv[4]);
  560.         return -1;
  561.     }
  562.     if(Mycall[0] == '\0'){
  563.         tputs("set mycall first\n");
  564.         return -1;
  565.     }
  566.     /* Note: More than one card can be supported if you give up a COM:
  567.      * port, thus freeing up an IRQ line and port address
  568.      */
  569.  
  570.     if(Egnbr >= EGMAX) {
  571.         tputs("Only 1 EAGLE controller supported right now!\n");
  572.         return -1;
  573.     }
  574.     dev = Egnbr++;
  575.  
  576.     /* Initialize hardware-level control structure */
  577.     Eagle[dev].addr = htoi(argv[1]);
  578.     Eagle[dev].vec = htoi(argv[2]);
  579.  
  580.     /* Save original interrupt vector */
  581.     Eagle[dev].oldvec = getirq(Eagle[dev].vec);
  582.  
  583.     /* Set new interrupt vector */
  584.     if(setirq(Eagle[dev].vec,eghandle[dev]) == -1){
  585.         tprintf("IRQ %u out of range\n",Eagle[dev].vec);
  586.         Egnbr--;
  587.         return -1;
  588.     }
  589.     /* Create interface structures and fill in details */
  590.     if_pca = (struct iface *)callocw(1,sizeof(struct iface));
  591.     if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
  592.  
  593.     if_pca->addr = if_pcb->addr = Ip_addr;
  594.     if(argc > 8)
  595.         if_pca->addr = resolve(argv[8]);
  596.     if(argc > 9)
  597.         if_pcb->addr = resolve(argv[9]);
  598.  
  599.     if(if_pca->addr == 0 || if_pcb->addr == 0){
  600.         tputs(Noipaddr);
  601.         free((char *)if_pca);
  602.         free((char *)if_pcb);
  603.         return -1;
  604.     }
  605.     /* Append "a" to interface associated with A channel */
  606.     cp = mallocw((unsigned)strlen(argv[4])+2);
  607.     strcpy(cp,argv[4]);
  608.     strcat(cp,"a");
  609.     if_pca->name = cp;
  610.     /* Append "b" to iface associated with B channel */
  611.     cp = mallocw((unsigned)strlen(argv[4])+2);
  612.     strcpy(cp,argv[4]);
  613.     strcat(cp,"b");
  614.     if_pcb->name = cp;
  615.  
  616.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  617.     if_pcb->type = if_pca->type = CL_AX25;
  618.     if_pcb->ioctl = if_pca->ioctl = eg_ctl;
  619.     if_pca->dev = 2*dev;            /* eg0a */
  620.     if_pcb->dev = 2*dev + 1;        /* eg0b */
  621.     if_pcb->stop = if_pca->stop = eg_stop;
  622.     if_pcb->output = if_pca->output = ax_output;
  623.     if_pcb->raw = if_pca->raw = eg_raw;
  624.     if_pca->iface_metric = if_pcb->iface_metric = 1;
  625.  
  626.     if(strcmp(argv[3],"ax25") == 0) {
  627.         /* Must be true, was checked at top */
  628.         if_pcb->send = if_pca->send = ax_send;
  629.         if(if_pcb->hwaddr == NULLCHAR)
  630.             if_pcb->hwaddr = mallocw(AXALEN);
  631.         memcpy(if_pcb->hwaddr,Mycall,AXALEN);
  632.         if(if_pcb->ipcall == NULLCHAR)
  633.             if_pcb->ipcall = mallocw(AXALEN);
  634.         memcpy(if_pcb->ipcall,Mycall,AXALEN);
  635.         if(if_pca->hwaddr == NULLCHAR)
  636.             if_pca->hwaddr = mallocw(AXALEN);
  637.         memcpy(if_pca->hwaddr,Mycall,AXALEN);
  638.         if(if_pca->ipcall == NULLCHAR)
  639.             if_pca->ipcall = mallocw(AXALEN);
  640.         memcpy(if_pca->ipcall,Mycall,AXALEN);
  641.     }
  642.     /* Link em in to the interface chain */
  643.     if_pca->next = if_pcb;
  644.     if_pcb->next = Ifaces;
  645.     Ifaces = if_pca;
  646.  
  647.     /* set params in egchan table for CHANNEL B */
  648.  
  649.     hp = &Egchan[2*dev+1];                /* eg1 is offset 1 */
  650.     hp->iface = if_pcb;
  651.     hp->stata = Eagle[dev].addr + CHANA + CTL;    /* permanent status */
  652.     hp->statb = Eagle[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  653.     hp->dmactrl = Eagle[dev].addr + DMACTRL;    /* Eagle control reg */
  654.     hp->speed = (int16)atoi(argv[7]);
  655.     hp->base = Eagle[dev].addr + CHANB;
  656.     hp->bufsiz = atoi(argv[5]);
  657.     hp->tstate = IDLE;
  658.     /* default KISS Params */
  659.     hp->txdelay = 25;        /* 250 Ms */
  660.     hp->persist = 64;        /* 25% persistence */
  661.     hp->slotime = 10;        /* 100 Ms */
  662.     hp->squeldelay = 20;        /* 200 Ms */
  663.  
  664.     write_scc(CTL+hp->stata,R9,FHWRES);     /* Hardware reset */
  665.                         /* one time only */
  666.     /* Disable interrupts with Master interrupt ctrl reg */
  667.     write_scc(CTL+hp->stata,R9,0);
  668.  
  669.     egchanparam(hp);
  670.  
  671.     /* Pre-allocate a receive buffer */
  672.     hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  673.     if(hp->rcvbuf == NULLBUF) {
  674.         /* No memory, abort receiver */
  675.         tputs("EGATTACH: No memory available for Receive buffers\n");
  676.         /* Restore original interrupt vector */
  677.         setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  678.         Egnbr--;
  679.         return(-1);
  680.     }
  681.     hp->rcp = hp->rcvbuf->data;
  682.     hp->rcvbuf->cnt = 0;
  683.     hp->sndq = NULLBUF;
  684.  
  685.     /* set params in egchan table for CHANNEL A */
  686.     hp = &Egchan[2*dev];            /* eg0a is offset 0 */
  687.     hp->iface = if_pca;
  688.     hp->speed = (int16)atoi(argv[7]);
  689.     hp->base = Eagle[dev].addr + CHANA;
  690.     hp->bufsiz = atoi(argv[5]);
  691.     hp->tstate = IDLE;
  692.     /* default KISS Params */
  693.     hp->txdelay = 25;        /* 250 Ms */
  694.     hp->persist = 64;        /* 25% persistence */
  695.     hp->slotime = 10;        /* 100 Ms */
  696.     hp->squeldelay = 20;        /* 200 Ms */
  697.  
  698.     egchanparam(hp);
  699.  
  700.     /* Pre-allocate a receive buffer */
  701.     hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  702.     if(hp->rcvbuf == NULLBUF) {
  703.         /* No memory, abort receiver */
  704.         tputs("EGATTACH: No memory available for Receive buffers\n");
  705.         /* Restore original interrupt vector */
  706.         setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  707.         Egnbr--;
  708.         return -1;
  709.     }
  710.     hp->rcp = hp->rcvbuf->data;
  711.     hp->rcvbuf->cnt = 0;
  712.     hp->sndq = NULLBUF;
  713.  
  714.     write_scc(CTL+hp->base,R9,MIE|NV);        /* master interrupt enable */
  715.  
  716.     /* Enable interrupts on the EAGLE card itself */
  717.     outportb(hp->dmactrl,INTENABLE);
  718.  
  719.     /* Enable interrupt */
  720.     maskon(Eagle[dev].vec);
  721.  
  722.     return 0;
  723. }
  724.  
  725.  
  726. /* Shut down interface */
  727. static int
  728. eg_stop(iface)
  729. struct iface *iface;
  730. {
  731.     int dev;
  732.  
  733.     dev = iface->dev;
  734.     if(dev & 1)
  735.         return 0;
  736.     dev >>= 1;    /* Convert back into eagle number */
  737.  
  738.     /* Turn off interrupts */
  739.     maskoff(Eagle[dev].vec);
  740.  
  741.     /* Restore original interrupt vector */
  742.     setirq(Eagle[dev].vec,Eagle[dev].oldvec);
  743.  
  744.     /* Force hardware reset */
  745.     write_scc(CTL+Eagle[dev].addr + CHANA,R9,FHWRES);
  746.  
  747.     /* resets interrupt enable on eagle card itself */
  748.     outportb(Eagle[dev].addr+DMACTRL,0);
  749.     return 0;
  750. }
  751.  
  752. /* Send raw packet on eagle card */
  753. static int
  754. eg_raw(iface,bp)
  755. struct iface *iface;
  756. struct mbuf *bp;
  757. {
  758.     char kickflag;
  759.     struct egchan *hp;
  760.  
  761.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  762.     iface->rawsndcnt++;
  763.     iface->lastsent = secclock();
  764.     hp = &Egchan[iface->dev];
  765.     kickflag = (hp->sndq == NULLBUF) & (hp->sndbuf == NULLBUF);    /* clever! flag=1 if something in queue */
  766.     enqueue(&hp->sndq,bp);
  767.     if(kickflag)            /* simulate interrupt to xmit */
  768.         egtxint(hp);        /* process interrupt */
  769.     return 0;
  770. }
  771. /* routine to delay n increments of 10 milliseconds
  772.  * about right on a turbo XT - will be slow on 4.77
  773.  * Still looking for a way to use the 8253 timer...
  774.  */
  775. static void
  776. waitmsec(n)
  777. int n;
  778. {
  779.     long i;
  780.  
  781.     for(i=0L; i < (200L*n); i++)
  782.         ;  /* simple loop delay */
  783. }
  784.  
  785. /* display EAGLE Channel stats */
  786. int
  787. doegstat(argc,argv,p)
  788. int argc;
  789. char *argv[];
  790. void *p;
  791. {
  792.     struct egchan *hp0, *hp1;
  793.     int i;
  794.  
  795.     for(i=0; i<EGMAX; i++) {
  796.         hp0 = &Egchan[i];
  797.         hp1 = &Egchan[i+1];
  798.  
  799.         tputs("EAGLE Board Statistics:\n\n");
  800.         tputs("Base Addr\tRxints\tTxints\tExints\tEnqued\tCrcerr\tAborts\tRxOvers\tRFrames\n");
  801.         tputs("---------\t------\t------\t------\t------\t------\t------\t-------\t-------\n");
  802.         tprintf("0x%x\t\t%ld\t%ld\t%ld\t%d\t%d\t%d\t%d\t%d\nRcv State=%s\n", hp0->base, hp0->rxints,
  803.             hp0->txints, hp0->exints, hp0->enqueued, hp0->crcerr, hp0->aborts,
  804.             hp0->rovers,hp0->rxframes,
  805.             hp0->rstate==0?"IDLE":hp0->rstate==1?"ACTIVE":hp0->rstate==2?"RXERROR":hp0->rstate==3?"RXABORT":"TOOBIG");
  806.  
  807.         tprintf("0x%x\t\t%ld\t%ld\t%ld\t%d\t%d\t%d\t%d\t%d\nRcv State=%s\n\n", hp1->base, hp1->rxints,
  808.             hp1->txints, hp1->exints, hp1->enqueued, hp1->crcerr, hp1->aborts,
  809.             hp1->rovers,hp1->rxframes,
  810.             hp1->rstate==0?"IDLE":hp1->rstate==1?"ACTIVE":hp1->rstate==2?"RXERROR":hp1->rstate==3?"RXABORT":"TOOBIG");
  811.     }
  812.     return 0;
  813. }
  814.  
  815. /* Subroutine to set kiss params in channel tables */
  816. static int32
  817. eg_ctl(iface,cmd,set,val)
  818. struct iface *iface;
  819. int cmd;
  820. int set;
  821. int32 val;
  822. {
  823.     struct egchan *hp;
  824.  
  825.     hp = &Egchan[iface->dev];        /* point to channel table */
  826.     switch(cmd){
  827.     case PARAM_TXDELAY:
  828.         if(set)
  829.             hp->txdelay = val;
  830.         return hp->txdelay;
  831.     case PARAM_PERSIST:
  832.         if(set)
  833.             hp->persist = val;
  834.         return hp->persist;
  835.     case PARAM_SLOTTIME:
  836.         if(set)
  837.             hp->slotime = val;
  838.         return hp->slotime;
  839.     case PARAM_TXTAIL:
  840.         if(set)
  841.             hp->squeldelay = val;
  842.         return hp->squeldelay;
  843.     }
  844.     return -1;
  845. }
  846. #endif /* EAGLE */
  847. #endif /* MSDOS */
  848.  
  849.